package com.shire.shire_interface.controller.api;

import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.shire.shire_interface.common.utils.JsonFormat;
import com.shire.shire_interface.common.utils.MathUtils;
import com.shire.shire_interface.common.utils.StrUtils;
import com.shire.shire_interface.constants.WxConstants;
import com.shire.shire_interface.constants.WxConstants.CmdStatus;
import com.shire.shire_interface.constants.WxConstants.CmdType;
import com.shire.shire_interface.constants.WxConstants.RetryCode;
import com.shire.shire_interface.constants.WxErrorCode;
import com.shire.shire_interface.controller.BaseController;
import com.shire.shire_interface.controller.kf.WebSocketController;
import com.shire.shire_interface.model.account.WxStation;
import com.shire.shire_interface.model.accounts.UserAccount;
import com.shire.shire_interface.model.command.WxCommand;
import com.shire.shire_interface.model.user.WxAccount;
import com.shire.shire_interface.service.account.WxAccountService;
import com.shire.shire_interface.service.chat.WxChatService;
import com.shire.shire_interface.service.commandcenter.BaseCommandProcessor;
import com.shire.shire_interface.service.commandcenter.WxCommandService;
import com.shire.shire_interface.service.friend.WxFriendLogService;
import com.shire.shire_interface.service.group.impl.WxGroupInviteService;
import com.shire.shire_interface.service.invite.WxInviteSubTaskService;
import com.shire.shire_interface.service.marketing.WxGroupTaskService;
import com.shire.shire_interface.service.massmsg.WxMassMsgItemService;
import com.shire.shire_interface.service.timeline.WxFriendTimelineService;
import com.shire.shire_interface.service.timeline.WxTimelineTaskService;
import com.shire.shire_interface.service.validation.WxValidationRecordService;
import com.shire.shire_interface.service.validation.WxValidationRuleService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;

//@Api(value = "指令接口",tags = "指令接口")
@RestController
@RequestMapping("/we")
public class ApiCommandController extends BaseController {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private BaseCommandProcessor baseCommandProcessor;

    @Autowired
    private WxAccountService accountService;

    @Autowired
    private WxCommandService commandService;

    @Autowired
    private WxChatService chatService;

    @Autowired
    private WxMassMsgItemService massMsgItemService;

    @Autowired
    private WxInviteSubTaskService inviteSubTaskService;

    @Autowired
    private WxGroupInviteService wxGroupInviteService;

    @Autowired
    private WxTimelineTaskService timelineTaskService;

    @Autowired
    private WxFriendLogService friendLogService;

    @Autowired
    private WxFriendTimelineService timelineService;
    @Autowired
    private WxGroupTaskService groupTaskService;
    @Autowired
    private WxValidationRuleService validationRuleService;
    @Autowired
    private WxValidationRecordService validationRecordService;

//    @ApiOperation(value = "查询微信账号下条指令")
//    @ApiImplicitParams(value = {@ApiImplicitParam(required = true, dataType = "int", name = "csId", value = "客服id"),
//            @ApiImplicitParam(required = true, dataType = "int", name = "wxAccount", value = "微信账号")})
//    @ApiResponses({@ApiResponse(code = 200, message = "调用成功返回", responseContainer = "List", response = WxCommand.class)})
    @ResponseBody
    @GetMapping(value = "/fetchCmd.wx")
    public Map<String, Object> fetchCmd(HttpServletRequest request, HttpServletResponse response) {
        WxStation station = getCurrentStation(request);

        if (station == null){
            return responseFailure("设备信息不存在");
        }
        WxAccount account = accountService.getWxAccountById(station.getWxaccountid());
        if (account == null)
            return responseFailure("需要绑定帐号");
        try{
            WxCommand wxCommand = baseCommandProcessor.getCommandForCS(account.getCsid(),account.getId());
            if(wxCommand==null){
                return new HashMap<>();
            }

            logger.info(("++++++++====== cmd id:"+wxCommand.getId()));

            Map<String, Object> reqMap = responseSuccess();
            response.addHeader("k", getK(request));
            response.addHeader("n", station.getStationno());
            WxConstants.CmdType cmdType = WxConstants.CmdType.get(wxCommand.getCmdtype());
            reqMap.put("cmdId", wxCommand.getId());
            reqMap.put("cmd", cmdType.getOp());
            reqMap.put("n", station.getStationno());
            reqMap.put("reqContent", JsonFormat.toMap(StrUtils.getNullStr(wxCommand.getReqcontent(), "{}")));
            return  reqMap;
        }
        catch (Exception e){
            logger.error("轮询获取指令异常[k="+getK(request)+"]：", e);
            return responseFailure(WxErrorCode.SYS_ERROR, "系统错误");
        }
    }


    @RequestMapping(value = "/testsync.wx")
    public Map<String, Object> syncAddress(HttpServletRequest request, @RequestBody String body) throws UnsupportedEncodingException {
        WxAccount account  = accountService.getWxAccountById(getCurrentStation(request).getWxaccountid());
        if (account == null)
            return responseFailure("需要绑定帐号");

        WxCommand command = commandService.genSyncAddressCmd(account);
        baseCommandProcessor.addCommand(account.getCsid(),account.getId(),command);
        return responseSuccess();
    }


    @RequestMapping(value = "/nodebug")
    public Map<String, Object> testNotLog(HttpServletRequest request, @RequestParam(value = "data_list") String data_list) throws UnsupportedEncodingException {
        logger.info(uncompress(data_list));
        return responseSuccess();
    }

    @RequestMapping(value = "/debug")
    public Map<String, Object> testLog(HttpServletRequest request, @RequestParam(value = "data_list") String data_list) throws UnsupportedEncodingException {
        logger.info(uncompress(data_list));
        return responseSuccess();
    }
    /**
     * 使用gzip进行解压缩
     */
    public static String uncompress(@RequestParam(value = "compressedStr") String compressedStr) {
        if (compressedStr == null) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = null;
        GZIPInputStream ginzip = null;
        byte[] compressed = null;
        String decompressed = null;
        try {
            compressed = new sun.misc.BASE64Decoder().decodeBuffer(compressedStr);
            in = new ByteArrayInputStream(compressed);
            ginzip = new GZIPInputStream(in);

            byte[] buffer = new byte[1024];
            int offset = -1;
            while ((offset = ginzip.read(buffer)) != -1) {
                out.write(buffer, 0, offset);
            }
            decompressed = out.toString();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ginzip != null) {
                try {
                    ginzip.close();
                } catch (IOException e) {
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
            try {
                out.close();
            } catch (IOException e) {
            }
        }
        return decompressed;
    }


//    @ApiOperation(value = "镜像指令")
//    @ApiImplicitParams(value = {@ApiImplicitParam(paramType = "header", required = true, dataType = "int", name = "csId", value = "客服id"),
//            @ApiImplicitParam(paramType = "header", required = true, dataType = "int", name = "wxAccount", value = "微信账号")})
//    @ApiResponses({@ApiResponse(code = 200, message = "调用成功返回", responseContainer = "List", response = WxFriend.class)})
    @ResponseBody
    @RequestMapping("/crkCmdMirror.wx")
    public Map<String, Object> crkCmdMirror(HttpServletRequest request, @RequestBody String body, @RequestParam(value = "csId")Integer csId, @RequestParam(value = "wxAccount")Integer wxAccount) {
        logger.info("收到指令镜像，body={}, k={}, n={}", body, csId, wxAccount);
        try{
            WxAccount account  = accountService.getWxAccountById(getCurrentStation(request).getWxaccountid());
            if (account == null)
                return responseFailure("需要绑定帐号");

            if(account==null){
                logger.debug("未找到微信位置，k={}, n={}", csId, wxAccount);
                return responseFailure("未找到微信位置");
            }
            JSONObject map = JSONObject.parseObject(body);
            String cmd = (String)map.get("cmd");
            WxConstants.CmdType cmdType = WxConstants.CmdType.get(cmd);
            if(cmdType==null || cmdType== WxConstants.CmdType.UNKNOWN){
                logger.debug("该指令类型不存在，k={}, n={}", csId, wxAccount);
                return responseFailure("该指令类型不存在");
            }

            if(cmdType==WxConstants.CmdType.CRK_PASS_FRIEND){
                if(account==null){
                    return responseFailure("账号不存在！");
                }
                if(account.getCreatetime()!= null  && account.getCreatetime().after(new Date(System.currentTimeMillis()-3*24*3600*1000))){
                    logger.info("新账号，前三天不自动通过添加好友, account={}", account.getAccount());
                    return responseFailure("新账号，前三天不自动通过添加好友！");
                }

                return responseSuccess("暂不自动添加好友");
            }

            commandService.addWxCommand(csId,wxAccount , cmdType, "{}", new Date());
            return responseSuccess();
        }
        catch (Exception e){
            logger.error("接收CRK镜像命令处理结果异常["+body+"]：", e);
            return responseFailure(WxErrorCode.SYS_ERROR, "系统错误");
        }
    }

//    @RequestMapping("/crkCmdScreen")
//    public Map<String, Object> crkCmdScreen(HttpServletRequest request, @RequestBody String body, Integer csId, Integer wxAccount) {
//        logger.info("收到截屏指令，body={}", body);
//        try{
//            WxStation wxStation = getWxStation(request);
//            if(wxStation==null){
//                return responseFailure("未找到微信位置");
//            }
//            Map<String, Object> map = JsonFormat.toMap(body);
//            Long cmdId = MathUtils.getMapLongValue(map, "cmdId", 0L);
//            String data = (String)map.get("data");
//            if(cmdId<=0 || StrUtils.isBlank(data)){
//                return responseFailure("参数错误！");
//            }
//            String rootPath = EnvConfigService.getString("client.deb");
//            String folder = EnvConfigService.getString("client.screen");
//            String imgFolder = rootPath + folder + wxStation.getId() + "/";
//            String fileName = cmdId+"_"+ DateUtils.getDatestr(new Date(), DateUtils.ymdhmsSdf)+".png";
//            logger.info("Screen, k={}, n={}, path={}", getK(request), getN(request), fileName);
//            Base64Img.generateImage(data, imgFolder, fileName);
//            return responseSuccess();
//        }
//        catch (Exception e){
//            logger.error("接收CRK镜像命令处理结果异常["+body+"]：", e);
//            return responseFailure(WxErrorCode.SYS_ERROR, "系统错误");
//        }
//    }

    /**
     * 接收crk返回命令处理结果
     * @param request
     * @return
     */
    @RequestMapping("/crkCmdResp.wx")
    public Map<String, Object> responseCmd(HttpServletRequest request, @RequestBody(required = false) String body) {
        logger.info("收到指令返回，body={}", body);
        try{

            Map<String, Object> map = (Map<String, Object>) JSONUtils.parse(body);
            Integer status = StrUtils.getIntValue(String.valueOf(map.get("status")), -1);
//            if(status!=10006) {
//                cmdProcessService.releaseDeviceLock(getK(request));
//            }
            Integer cmdId = MathUtils.getMapIntValue(map,"cmdId", -1);
            if(cmdId==-1 && status==0){
                logger.debug("CRK自我指令完成！！！, body={}", body);
                return responseSuccess("ok");
            }
            WxCommand wxCommand = commandService.getCommandById(cmdId);
            if(wxCommand==null){
                logger.warn("收到CRK指令响应，指令ID缺失或不存在[{}]", body);
                return responseFailure(WxErrorCode.INVALID_PARAMETER,"Invalid cmdId value.");
            }
            if(status==10006){ // 指令重发，添加回队列顶部
                wxCommand.setCmdstatus(WxConstants.CmdStatus.WAIT.getCode());
                //TODO: 指令重试？
//                cmdProcessService.addCmdHeader(wxCommand);
                commandService.updateWxCommand(wxCommand);
                return responseSuccess("ok");
            }

            if(wxCommand.getCmdstatus()==WxConstants.CmdStatus.SUCCESSED.getCode() || wxCommand.getCmdstatus()==WxConstants.CmdStatus.FAILED.getCode()){
                // 该指令已经处理过，丢弃该请求
                return responseSuccess("ok");
            }
            // 将设备处理器忙碌状态取消
//            cmdProcessService.releaseDeviceLock(wxCommand);

            WxConstants.CmdStatus cmdStatus = null;
            if(status>=0){
                cmdStatus = WxConstants.CmdStatus.SUCCESSED;
            }
            else{
                cmdStatus = CmdStatus.FAILED;
            }
            wxCommand.setRststatus(status);
            Map<String, Object> respContent = (Map<String, Object>)map.get("respContent");
            wxCommand.setRespcontent(JSONUtils.toJSONString(respContent));
            wxCommand.setCmdstatus(cmdStatus.getCode());

            if(status>0){
                RetryCode retryCode = RetryCode.get(status);
                if(retryCode!=null){
                    int maxTimes = 2;
                    CmdType cmdType = CmdType.get(wxCommand.getCmdtype());
                    if(cmdType==CmdType.CRK_SEND_CHAT
                            || cmdType==CmdType.CRK_ACCEPT_CARD
                            || cmdType==CmdType.CRK_ADD_WXID
                            || cmdType==CmdType.CRK_ADD_FRIEND){
                        maxTimes = 2;
                    }
                    else if(cmdType==CmdType.CRK_JOIN_GROUP){
                        maxTimes = 2;
                    }
                    if(wxCommand.getTrytimes()<maxTimes){
                        wxCommand.setCmdstatus(CmdStatus.NEW.getCode());
                        wxCommand.setRststatus(WxErrorCode.INIT_VALUE);
                        wxCommand.setTrytimes(wxCommand.getTrytimes() + 1);
                        // 设置延迟时间
                        int delaySeconds = retryCode.getDelaySeconds();
                        wxCommand.setStarttime(new Date(System.currentTimeMillis() + delaySeconds * 1000L));
                        if(wxCommand.getEndtime()!=null) {
                            wxCommand.setEndtime(new Date(wxCommand.getEndtime().getTime() + delaySeconds * 1000L));
                        }
                        commandService.updateWxCommand(wxCommand);
                        return responseSuccess("ok");
                    }
                }
            }

            wxCommand.setUpdatetime(new Date());
            commandService.updateWxCommand(wxCommand);
            baseCommandProcessor.responseCommand(wxCommand.getCsid(),wxCommand.getAccountid(),wxCommand);
            WxConstants.CmdType cmdType = WxConstants.CmdType.get(wxCommand.getCmdtype());
            switch (cmdType){
                case CRK_SEND_CHAT:
                case CRK_SEND_CHAT_D:
                case CRK_SCAN_IMAGE:
                case CRK_ACCEPT_CARD:
                case CRK_SEND_CHAT_D_FILE:
                case CRK_SEND_CHAT_D_IMAGE:
                case CRK_SEND_CHAT_D_NAMECARD:
                case CRK_SEND_CHAT_D_VIDEO:
                case CRK_SEND_CHAT_D_LINK:
                case CRK_SEND_CHAT_BATCH_D:
                case CRK_UPDATE_GROUP_DESC_D:
                    chatService.respSendChat(wxCommand, respContent);
                    break;
                case CRK_JOIN_GROUP:
                    chatService.respJoinGroup(wxCommand);
                    break;
                case CRK_INVITE_GROUP:
                    wxGroupInviteService.respInviteGroup(wxCommand);
                    break;
                case CRK_ADD_FRIEND:
                    break;
                case CRK_ADD_WXID:
                    friendLogService.updateFriendLogByCmd(wxCommand);
                    break;
                case CRK_SEND_LINK:
//                    wxAdItemService.respSendAdItem(wxCommand);
                    break;
                case CRK_QUIT_GROUP:
//                    wxGroupService.respQuitGroup(wxCommand);
                    break;
                case CRK_SEND_TIMELINE_LINK_D:
                case CRK_SEND_TIMELINE_IMAGE_D:
                case CRK_SEND_TIMELINE_VIDEO_D:
                case CRK_SEND_TIMELINE_TEXT_D:
                    timelineTaskService.updateTimelineTaskByCommand(wxCommand);
                    break;
                case CRK_FETCH_TIMELINE_D:
                case CRK_FETCH_USERTIMELINE_D:
                    JSONObject jsonObject = JSONObject.parseObject(body);
                    timelineService.recieveTimeline(wxCommand, jsonObject.getJSONObject("respContent"));
                    JSONObject ws = new JSONObject();
                    ws.put("opType",7);
                    List<UserAccount> list = accountService.getSystemUserByWxid(accountService.getWxAccountById(wxCommand.getAccountid()).getWxid());
                    for(UserAccount acc : list) {
                        WebSocketController.sendMessage(acc.getUserId()+ "", ws.toJSONString());
                    }
                    break;
                case CRK_CREATE_GROUP_D:
                    groupTaskService.updateGroupTaskItemByCmdId(wxCommand, respContent);
                    break;
                case CRK_HELLO_VERIFY_D:
                    validationRecordService.updateRecordByCmd(wxCommand);
                    validationRuleService.syncValidationList(wxCommand.getCsid(),wxCommand.getAccountid());
                    break;
                case CRK_HELLO_FETCH_D:
                    if (respContent.containsKey("hellos"))
                        validationRecordService.syncValidationForAccount(accountService.getWxAccountById(wxCommand.getAccountid()),JSONArray.parseArray(JSONUtils.toJSONString(respContent.get("hellos"))));
                    break;
                case CRK_UPDATE_PROFILE:
                    accountService.accountUpdated(wxCommand);
                    break;
                default:
                    break;
            }

            WxConstants.CmdTaskType taskType = WxConstants.CmdTaskType.get(wxCommand.getTasktype());
            switch (taskType){
                case UNKNOWN:
                    break;
                case INVITE:
                    inviteSubTaskService.updateSubTaskRststatus(wxCommand.getTaskid(),wxCommand.getRststatus());
                    break;
                case MASSMSG:
                    massMsgItemService.updateItem(wxCommand.getTaskid(), wxCommand.getRststatus());
                    break;
                case JOINGROUP:
                    break;
                case TIMLIMELINE:
                    break;
                default:
                        break;
            }
            return responseSuccess("ok");
        }
        catch (Exception e){
            logger.error("接收CRK命令处理结果异常["+body+"]：", e);
            return responseFailure(WxErrorCode.SYS_ERROR, "系统错误");
        }

    }

}
